﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;

namespace Dashboard.Hubs
{
	public class HealthStatusView
	{
		public double FreeRam { get; set; }
		public double UsedRam { get; set; }
		public int DiskUsage { get; set; }
		public int CpuUsage { get; set; }
		public double FreeHDD { get; set; }
		public double UsedHDD { get; set; }
	}

	public class AveragedHealthStatusView
	{
		public double TotalRam { get; set; }
		public double UsedRam { get; set; }
		public double DiskUsage { get; set; }
		public double CpuUsage { get; set; }
	}

	public class HealthMonitor
	{
		private static HealthMonitor instance;

		Microsoft.VisualBasic.Devices.ComputerInfo computerInfo;
		PerformanceCounter cpuCounter;
		PerformanceCounter diskIdleCounter;
		DriveInfo cDrive;

		public static int Step
		{
			get
			{
				return 100;
			}
			private set { }
		}

		private HealthMonitor()
		{
			computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo();

			cpuCounter = new PerformanceCounter(
				"Processor",
				"% Processor Time",
				"_Total");

			var perfCategory = new PerformanceCounterCategory("PhysicalDisk");
			string[] instanceNames = perfCategory.GetInstanceNames();

			string driveName = string.Empty;
			foreach (string name in instanceNames)
			{
				if (name.IndexOf("C:") > 0)
				{
					if (string.IsNullOrEmpty(driveName))
						driveName = name;
				}
			}

			diskIdleCounter = new PerformanceCounter(
				"PhysicalDisk",
				"% Idle Time",
				driveName);

			cDrive = new DriveInfo("C");
		}

		static HealthMonitor()
		{
			instance = new HealthMonitor();
		}

		private HealthStatusView GetHealthStatus()
		{
			var result = new HealthStatusView()
			{
				UsedRam = (computerInfo.TotalPhysicalMemory - computerInfo.AvailablePhysicalMemory) / 1024 / 1024,
				FreeRam = computerInfo.AvailablePhysicalMemory / 1024 / 1024,
				DiskUsage = 100 - (int)diskIdleCounter.NextValue(),
				CpuUsage = (int)cpuCounter.NextValue()
			};

			if (cDrive.IsReady)
			{
				result.FreeHDD = cDrive.TotalFreeSpace / 1024 / 1024 / 1024;
				result.UsedHDD = (cDrive.TotalSize - cDrive.TotalFreeSpace) / 1024 / 1024 / 1024;
			}

			return result;
		}

		public static void Run()
		{
			Thread t = new Thread(delegate()
			{
				while (true)
				{
					Thread.Sleep(HealthMonitor.Step);
					Post(instance.GetHealthStatus());
				}
			}
			);

			t.Start();
		}

		private List<Tuple<DateTime, HealthStatusView>> history = new List<Tuple<DateTime, HealthStatusView>>();

		private static void Post(HealthStatusView status)
		{
			instance.history.Add(new Tuple<DateTime, HealthStatusView>(
				DateTime.UtcNow,
				status
			));

			MosaicHub.PostHealthStatus(status);
		}

		public static List<Tuple<DateTime, AveragedHealthStatusView>> BySeconds()
		{
			var x = from h in instance.history
					group h by new DateTime(
						h.Item1.Year, h.Item1.Month, h.Item1.Day, 
						h.Item1.Hour, h.Item1.Minute, h.Item1.Second, DateTimeKind.Utc) into bySeconds
					select new Tuple<DateTime, AveragedHealthStatusView>(
						bySeconds.Key,
						new AveragedHealthStatusView()
						{
							CpuUsage = bySeconds.Average(o => o.Item2.CpuUsage),
							DiskUsage = bySeconds.Average(o => o.Item2.DiskUsage),
							UsedRam = bySeconds.Average(o => o.Item2.UsedRam),
							TotalRam = bySeconds.First().Item2.UsedRam + bySeconds.First().Item2.FreeRam
						});

			return x.ToList();
		}

		public static List<Tuple<DateTime, HealthStatusView>> FullHistory
		{
			get
			{
				return instance.history;
			}
			private set { }
		}
	}
}